package cn.jtfadmin.sysmonitor.service;

import cn.jtfadmin.sysmonitor.domain.dto.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import oshi.SystemInfo;
import oshi.hardware.*;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.FormatUtil;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;

/**
 * 系统信息服务类
 * @author jtf
 * @since 0.0.2
 */
@Service
public class SystemInfoService {

    /**
     * 获取磁盘信息
     * @return
     */
    public List<DiskInfoDTO> getDiskInfo() {
        return getDiskInfo(getSystemInfo());
    }

    private List<DiskInfoDTO> getDiskInfo(SystemInfo systemInfo){
        List<HWDiskStore> diskStores = systemInfo.getHardware().getDiskStores();
        List<DiskInfoDTO> list = new ArrayList<>(diskStores.size());
        for (HWDiskStore diskStore : diskStores) {
            DiskInfoDTO diskInfoDTO = new DiskInfoDTO();
            diskInfoDTO.setName(diskStore.getName());
            diskInfoDTO.setModel(diskStore.getName());
            diskInfoDTO.setSerial(diskStore.getSerial());
            diskInfoDTO.setSize(diskStore.getSize());
            diskInfoDTO.setDisplaySize(diskStore.getSize()>0L? FormatUtil.formatBytesDecimal(diskStore.getSize()) : "?");
            diskInfoDTO.setReads(diskStore.getReads());
            diskInfoDTO.setReadBytes(diskStore.getReadBytes());
            diskInfoDTO.setDisplayReadBytes(diskStore.getReads()>0? FormatUtil.formatBytes(diskStore.getReadBytes()) : "?");
            diskInfoDTO.setWrites(diskStore.getWrites());
            diskInfoDTO.setWriteBytes(diskStore.getWriteBytes());
            diskInfoDTO.setDisplayWriteBytes(diskStore.getWrites()>0L ? FormatUtil.formatBytes(diskStore.getWriteBytes()) : "?");
            diskInfoDTO.setTransferTime(diskStore.getTransferTime());
            List<HWPartition> sysPartitions = diskStore.getPartitions();
            List<DiskInfoDTO.PartitionDTO> partitions = new ArrayList<>(sysPartitions.size());
            for (HWPartition sysPartition : sysPartitions) {
                DiskInfoDTO.PartitionDTO partitionDTO = new DiskInfoDTO.PartitionDTO(
                        sysPartition.getIdentification(),
                        sysPartition.getName(),
                        sysPartition.getType(),
                        sysPartition.getUuid(),
                        sysPartition.getSize(),
                        FormatUtil.formatBytesDecimal(sysPartition.getSize()),
                        sysPartition.getMajor(),
                        sysPartition.getMinor(),
                        sysPartition.getMountPoint()
                );

                partitions.add(partitionDTO);
            }

            if(!CollectionUtils.isEmpty(partitions)){
                diskInfoDTO.setPartitions(partitions);
            }
            list.add(diskInfoDTO);
        }

        return list;
    }

    /**
     * 获取计算机硬件信息
     * @return 计算机硬件信息
     */
    public ComputerSystemInfoDTO getComputerSystemInfo(){
        SystemInfo systemInfo = getSystemInfo();
        return getComputerSystemInfo(systemInfo);
    }
    private ComputerSystemInfoDTO getComputerSystemInfo(SystemInfo systemInfo){
        HardwareAbstractionLayer hardware = systemInfo.getHardware();
        ComputerSystem computerSystem = hardware.getComputerSystem();
        Baseboard baseboard = computerSystem.getBaseboard();
        Firmware firmware = computerSystem.getFirmware();
        return new ComputerSystemInfoDTO(
                computerSystem.getManufacturer(),
                computerSystem.getModel(),
                computerSystem.getSerialNumber(),
                computerSystem.getHardwareUUID(),
                baseboard.getManufacturer(),
                baseboard.getModel(),
                baseboard.getVersion(),
                baseboard.getSerialNumber(),
                firmware.getManufacturer(),
                firmware.getName(),
                firmware.getDescription(),
                firmware.getVersion(),
                firmware.getReleaseDate()
        );
    }

    /**
     * 获取cpu信息
     * @return cpu 信息
     */
    public ProcessorInfoDTO getProcessorInfo(){
        return getProcessorInfo(getSystemInfo());
    }

    private ProcessorInfoDTO getProcessorInfo(SystemInfo systemInfo) {
        CentralProcessor processor = systemInfo.getHardware().getProcessor();
        return new ProcessorInfoDTO(
          processor.getProcessorIdentifier().getName(),
          processor.getPhysicalPackageCount(),
          processor.getPhysicalProcessorCount(),
          processor.getLogicalProcessorCount(),
          processor.getProcessorIdentifier().getIdentifier(),
          processor.getProcessorIdentifier().getProcessorID(),
          processor.getProcessorIdentifier().getMicroarchitecture()
        );
    }


    /**
     * 获取内存信息
     * @return
     */
    public MemoryInfoDTO getMemoryInfo(){
        return getMemoryInfo(getSystemInfo());
    }


    private MemoryInfoDTO getMemoryInfo(SystemInfo systemInfo){
        GlobalMemory memory = systemInfo.getHardware().getMemory();
        MemoryInfoDTO dto = new MemoryInfoDTO();
        dto.setAvailable(memory.getAvailable());
        dto.setTotal(memory.getTotal());
        dto.setDisplayAvailable(FormatUtil.formatBytes(dto.getAvailable()));
        dto.setDisplayTotal(FormatUtil.formatBytes(dto.getTotal()));
        return dto;
    }


    //*************************操作系统************************

    /**
     * 获取操作系统信息
     * @return 操作系统信息
     */
    public OperatingSystemInfoDTO getOperatingSystemInfo(){
        return getOperatingSystemInfo(getSystemInfo());
    }

    private OperatingSystemInfoDTO getOperatingSystemInfo(SystemInfo systemInfo){
        OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
        return new OperatingSystemInfoDTO(
                operatingSystem.getSystemUptime(),
                FormatUtil.formatElapsedSecs(operatingSystem.getSystemUptime()),
                operatingSystem.getSystemBootTime(),
                LocalDateTime.ofInstant(
                        Instant.ofEpochSecond(operatingSystem.getSystemBootTime()),ZoneOffset.systemDefault()
                ),
                operatingSystem.isElevated(),
                operatingSystem.getManufacturer(),
                operatingSystem.getFamily(),
                operatingSystem.getVersionInfo().getVersion()

        );
    }


    /**
     * 获取文件系统
     * @return 文件系统
     */
    public FileSystemDTO getFileSystem(){
        SystemInfo systemInfo = getSystemInfo();
        return getFileSystem(systemInfo);
    }

    private FileSystemDTO getFileSystem(SystemInfo systemInfo){
        FileSystem fileSystem = systemInfo.getOperatingSystem().getFileSystem();
        FileSystemDTO fileSystemDTO = new FileSystemDTO();
        fileSystemDTO.setOpenFileDescriptors(fileSystem.getOpenFileDescriptors());
        fileSystemDTO.setMaxFileDescriptors(fileSystem.getMaxFileDescriptors());
        List<OSFileStore> sysFileStores = fileSystem.getFileStores(true);
        List<FileSystemDTO.FileStoreDTO> fileStores = new ArrayList<>(sysFileStores.size());
        for (OSFileStore sysFileStore : sysFileStores) {
            FileSystemDTO.FileStoreDTO fileStoreDTO = new FileSystemDTO.FileStoreDTO(
                    sysFileStore.getName(),
                    sysFileStore.getVolume(),
                    sysFileStore.getLabel(),
                    sysFileStore.getLogicalVolume(),
                    sysFileStore.getMount(),
                    sysFileStore.getDescription(),
                    sysFileStore.getType(),
                    sysFileStore.getOptions(),
                    sysFileStore.getUUID(),
                    sysFileStore.getFreeSpace(),
                    FormatUtil.formatBytesDecimal(sysFileStore.getFreeSpace()),
                    sysFileStore.getUsableSpace(),
                    FormatUtil.formatBytesDecimal(sysFileStore.getUsableSpace()),
                    sysFileStore.getTotalSpace(),
                    FormatUtil.formatBytesDecimal(sysFileStore.getTotalSpace()),
                    sysFileStore.getFreeInodes(),
                    sysFileStore.getTotalInodes()
            );
            fileStores.add(fileStoreDTO);
        }

        fileSystemDTO.setFileStores(fileStores);
        return fileSystemDTO;
    }


    private SystemInfo getSystemInfo(){
        return new SystemInfo();
    }
}
